package com.newy.service.sys;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.newy.core.AppException;
import com.newy.core.BaseService;
import com.newy.core.util.LangUtils;
import com.newy.dao.sys.ParamDao;
import com.newy.domain.sys.Param;
import com.newy.domain.sys.vo.ParamDef;

/**
 * 
 * @author linzongxue 2012-2-18
 *
 */
@Service
@Transactional
public class ParamService extends BaseService{
	private static Logger logger = LoggerFactory.getLogger(ParamService.class);
	private static final String PARAM_DEF_PATH = "/paramDef.js";
	
	@Resource private ParamDao paramDao;
	
	/**
	 * 保存了从参数配置文件中读取的参数定义
	 */
	private static Map<String, ParamDef> paramDefs = new LinkedHashMap<String, ParamDef>();
	
	/**
	 * 获取字符串类型的系统参数
	 */
	public String getSysString(String name){
		return this.getParam(name, null).getValue();
	}

	/**
	 * 获取Long类型的系统参数
	 */
	public Long getSysLong(String name){
		return new Long(this.getParam(name, null).getValue());
	}
	
	/**
	 * 获取字符串类型的系统参数
	 */
	public String getUserString(String name, Long userId){
		return this.getParam(name, userId).getValue();
	}
	
	/**
	 * 获取Long类型的系统参数
	 */
	public Long getUserLong(String name, Long userId){
		return new Long(this.getParam(name, userId).getValue());
	}
	
	public Param getSysParam(String name){
		return this.getParam(name, null);
	}
	
	public Param getUserParam(String name, Long userId){
		return this.getParam(name, userId);
	}

	/**
	 * 获取所有系统参数定义，并在各个参数定义中设置当前值
	 */
	public List<ParamDef> getAllSysParams(){
		List<ParamDef> result = new ArrayList<ParamDef>();
		for (ParamDef paramDef : paramDefs.values()){
			if (paramDef.getType() == ParamDef.Type.sys){
				paramDef.setValue(this.getSysString(paramDef.getName())); //设置当前值
				result.add(paramDef);
			}
		}
		return result;
	}
	
	public void updateSysParam(String name, String value){
		this.updateParam(name, value, null);
	}
	
	public void updateUserParam(String name, String value, Long userId){
		this.updateParam(name, value, userId);
	}


	/**
	 * 从配置文件中加载参数定义
	 */
	public void initParamDefs(){
		logger.info("正在加载参数定义……");
		try {
			Reader reader = new InputStreamReader(getClass().getResourceAsStream(PARAM_DEF_PATH), "utf-8");
			ObjectMapper mapper = new ObjectMapper();
			mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
			mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
			mapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
			for(JsonNode node : mapper.readTree(reader)){
				ParamDef paramDef = mapper.convertValue(node, ParamDef.class);
				paramDefs.put(paramDef.getName(), paramDef);
			}
		} catch (IOException e) {
			throw new RuntimeException("读取参数定义文件(" + PARAM_DEF_PATH + ")失败：" + e.getMessage());
		}
	}
	
	/**
	 * 获取参数，如果在数据库获取不到，则说明使用参数定义中的初始值，获取初始值后同时在数据库中保存该值
	 * @param name 参数名称
	 * @param userId 参数关联的用户ID，如果为null表示是系统参数
	 */
	private Param getParam(String name, Long userId){
		//从数据库中读取
		Param param = paramDao.findByName(name, userId);
		if (param != null){
			return param;
		}
		//获取默认值，并添加到数据库中
		ParamDef paramDef = paramDefs.get(name);
		if (paramDef == null){
			throw new RuntimeException("获取参数出错：不存在名为的(" + name + ")的参数定义");
		}
		param = new Param();
		param.setName(name);
		param.setValue(paramDef.getDefaultValue().toString());
		param.setUserId(userId);
		paramDao.save(param);
		return param;
	}

	private void updateParam(String name, String value, Long userId){
		ParamDef def = paramDefs.get(name);
		if (def == null)
			throw new AppException("没有这个名称的参数定义：%s", name);
		if (!def.isEditable())
			throw new AppException("参数(%s)不允许修改");
		if (LangUtils.isNotEmpty(def.getValues()) && !def.getValues().contains(value))
			throw new AppException("参数(%s)不允许设置为该值：%s", name, value);

		Param param = paramDao.findByName(name, userId);
		param.setValue(value);
		paramDao.save(param);
	}
}
